﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Windows.Input;
using CredentialsManager.Helpers;
using CredentialsManager.Properties;
using MVVMFoundation;

namespace CredentialsManager.ViewModels
{
    public class UpdatePasswordQuestionViewModel : PasswordViewModel
    {
        #region Private classes

        private class UpdateWorkerInput : SetupWorkerInput
        {
            public string OldAnswer { get; set; }
            public string NewQuestion { get; set; }
            public string NewAnswer { get; set; }
        }

        #endregion

        #region Private member variables

        private string m_NewSecurityQuestion;
        private string m_NewSecurityAnswer;
        private BackgroundWorker m_UpdateWorker;
        private RelayCommand m_UpdateCommand;

        #endregion

        #region Constructors

        public UpdatePasswordQuestionViewModel(string displayName, string application,
            string userName, PasswordSettings passwordSettings)
            : base(displayName, userName, application, passwordSettings)
        {
            m_UpdateWorker = new BackgroundWorker();
            m_UpdateWorker.Initialise(m_UpdateWorker_DoWork,
                m_UpdateWorker_RunWorkerCompleted, null, false);
        }

        public UpdatePasswordQuestionViewModel(string application, string userName,
            PasswordSettings passwordSettings)
            : this(Resources.UpdatePasswordQuestionWindowTitle, application,
                userName, passwordSettings)
        { }
        
        #endregion

        #region Background worker handlers

        private void m_UpdateWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var input = e.Argument as UpdateWorkerInput;
            Debug.Assert(input != null);

            var proxy = ProxyFactory.Create<MembershipManagerClient, IMembershipManager>(
                ServiceAddressList.CredentialsService);

            try
            {
                proxy.UpdatePasswordQuestion(input.Application, input.UserName,
                    input.OldAnswer, input.NewQuestion, input.NewAnswer);
            }
            finally
            {
                ProxyFactory.Cleanup<MembershipManagerClient, IMembershipManager>(proxy);
            }
        }

        private void m_UpdateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                ErrorHandler.HandleNonSpecificWCFException(e.Error, this.DisplayName);
            }
            else
            {
                this.OnRequestClose();
            }

            this.IsLoading = false;
        }

        #endregion

        #region Public properties

        public string NewSecurityQuestion
        {
            get
            {
                return m_NewSecurityQuestion;
            }
            set
            {
                m_NewSecurityQuestion = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
                Validate();
            }
        }

        public string NewSecurityAnswer
        {
            get
            {
                return m_NewSecurityAnswer;
            }
            set
            {
                m_NewSecurityAnswer = value;
                RaisePropertyChanged(MethodBase.GetCurrentMethod().GetPropertyName());
                Validate();
            }
        }

        #endregion

        #region Protected methods

        protected override void Validate()
        {
            this.IsValid = false;

            if (!string.IsNullOrEmpty(this.NewSecurityQuestion) &&
                this.NewSecurityQuestion.Trim() != string.Empty &&
                !string.IsNullOrEmpty(this.NewSecurityAnswer) &&
                this.NewSecurityAnswer.Trim() != string.Empty)
            {
                this.IsValid = true;
            }
        }

        protected override void HandleNoPasswordQuestion()
        {
            this.SecurityQuestion = null;
        }

        #endregion

        #region Private methods

        private void Update()
        {
            if (!this.IsValid)
            {
                throw new InvalidOperationException(
                    Resources.CannotUpdateUserInvalidOperationException);
            }

            var input = new UpdateWorkerInput()
            {
                Application = this.Application,
                UserName = this.UserName,
                OldAnswer = this.SecurityAnswer,
                NewQuestion = this.NewSecurityQuestion,
                NewAnswer = this.NewSecurityAnswer
            };

            this.IsLoading = true;
            this.ProgressMessage = Resources.UpdatePasswordQuestionProgressMessage;                
            m_UpdateWorker.RunWorkerAsync(input);
        }

        #endregion

        #region Commands

        public ICommand UpdateCommand
        {
            get
            {
                return m_UpdateCommand ?? (m_UpdateCommand = new RelayCommand(
                    param => this.Update()));
            }
        }

        #endregion
    }
}
